#include "mainwindow.h"
#include <iostream>
#include "font.h"
using namespace std;

MainWindow::MainWindow(ALLEGRO_DISPLAY *pDisplay)
: View(Rect(), NULL), m_quit(false), m_lastFlip(0), 
  m_pDisplay(pDisplay), m_pQueue(NULL) {

     // set initial size / position
     int w = al_get_display_width(m_pDisplay);
     int h = al_get_display_height(m_pDisplay);
     m_rect.setWidth(w);
     m_rect.setHeight(h);
     int x=0, y=0;
     al_get_window_position(m_pDisplay, &x, &y);
     m_windowPos.setX(x);
     m_windowPos.setY(y);
}

MainWindow::~MainWindow() {
}

void MainWindow::handleEvents() {
          // create event queue
     m_pQueue = al_create_event_queue();
     // register event sources
     ALLEGRO_EVENT_SOURCE* pSource = al_get_display_event_source(m_pDisplay);
     al_register_event_source(m_pQueue, pSource);
     pSource = al_get_keyboard_event_source();
     al_register_event_source(m_pQueue, pSource);
     pSource = al_get_mouse_event_source();
     al_register_event_source(m_pQueue, pSource);

     // event loop
     ALLEGRO_EVENT event;
     ALLEGRO_KEYBOARD_STATE keyState;
     ALLEGRO_MOUSE_STATE mouseState;
     Point p(0,0), dp(0,0);
     while (!m_quit) {
	  if (!al_event_queue_is_empty(m_pQueue)) {
	       al_get_next_event(m_pQueue, &event);
	       switch (event.type) {
	       case ALLEGRO_EVENT_KEY_DOWN:
		    keyDown(event.keyboard.keycode, event.keyboard.modifiers,
			    event.keyboard.unichar);
		    break;
	       case ALLEGRO_EVENT_KEY_REPEAT:
		    al_get_keyboard_state(&keyState);
		    // do the event if the key is still down
		    if (al_key_down(&keyState, event.keyboard.keycode))
			 keyDown(event.keyboard.keycode, event.keyboard.modifiers,
				 event.keyboard.unichar);
		    break;
	       case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
		    p.setX(event.mouse.x);
		    p.setY(event.mouse.y);
		    mouseDown(p, event.mouse.button);
		    break;
	       case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
		    p.setX(event.mouse.x);
		    p.setY(event.mouse.y);
		    mouseUp(p, event.mouse.button);
		    break;
	       case ALLEGRO_EVENT_MOUSE_AXES:
		    // get current x/y values so there is less lag
		    al_get_mouse_state(&mouseState);
		    p.setX(al_get_mouse_state_axis(&mouseState, 0));
		    p.setY(al_get_mouse_state_axis(&mouseState, 1));
		    dp.setX(event.mouse.dx);
		    dp.setY(event.mouse.dy);
		    mouseMove(p, dp);
		    break;
	       case ALLEGRO_EVENT_DISPLAY_RESIZE:
		    al_acknowledge_resize(event.display.source);
		    al_flush_event_queue(m_pQueue);
		    setRect(Rect(0, 0, al_get_display_width(m_pDisplay), al_get_display_height(m_pDisplay)));
		    break;
	       case ALLEGRO_EVENT_DISPLAY_EXPOSE:
		    paint(true);
		    break;
	       case ALLEGRO_EVENT_DISPLAY_CLOSE:
		    // quit if window is closed
		    m_quit = true;
		    break;
	       }
	  }
	  // check for window move - needs redrawing on some displays
	  int x=0, y=0;
	  al_get_window_position(m_pDisplay, &x, &y);
	  if (x != m_windowPos.x() || y != m_windowPos.y()) {
	       paint(true); // force all views to redraw
	       m_windowPos.setX(x);
	       m_windowPos.setY(y);
	  }

	  // update any values which may have changed
	  // todo - get rid of this, update all with signals/slots
	  update();
	  // check if we need redrawing
	  if (secsSinceFlip() >= secsPerFrame()) {
	       paint();
	       if (m_needFlip) {
		    al_flip_display();
		    m_lastFlip = al_current_time();
		    m_needFlip = false;
	       }
	  }
     }
}

double MainWindow::secsSinceFlip() {
     return al_current_time();
}

double MainWindow::secsPerFrame() {
     return 1 / MainWindow::MaxFramerate;
}
